#include "main.h"
#include "includes.h"


/* 任务句柄 */
TaskHandle_t app_task_init_handle       = NULL;  //初始化任务句柄
TaskHandle_t app_task_led_handle 		= NULL;  //LED灯任务句柄
TaskHandle_t app_task_beep_handle 		= NULL;  //蜂鸣器任务句柄
TaskHandle_t app_task_key_handle 		= NULL;  //开发板按钮任务句柄
TaskHandle_t app_task_keyboard_handle 	= NULL;  //矩阵键盘任务句柄
TaskHandle_t app_task_rfid_handle 		= NULL;  //RFID任务句柄
TaskHandle_t app_task_rfid_rw_handle 	= NULL;  //RFID读写任务句柄
//TaskHandle_t app_task_paj7620_handle 	= NULL;  //手势识别任务句柄
TaskHandle_t app_task_oled_handle 		= NULL;  //OLED任务句柄
TaskHandle_t app_task_infra_red_handle 	= NULL;  //红外任务句柄
TaskHandle_t app_task_dht_handle 		= NULL;  //DHT11任务句柄
TaskHandle_t app_task_rtc_handle 		= NULL;  //RTC任务句柄
TaskHandle_t app_task_usart_handle 		= NULL;  //串口任务句柄
TaskHandle_t app_task_mqtt_recv_handle 	= NULL;  //MQTT接收任务句柄
TaskHandle_t app_task_mqtt_heart_handle = NULL;  //MQTT心跳包任务句柄
TaskHandle_t app_task_mqtt_send_handle 	= NULL;  //MQTT发送任务句柄
TaskHandle_t app_task_menu_handle		= NULL;  //菜单任务句柄
TaskHandle_t app_task_sr04_handle 		= NULL;  //超声波任务句柄
TaskHandle_t app_task_adc_flame_handle 	= NULL;  //火焰传感器任务句柄
TaskHandle_t app_task_adc_gas_handle 	= NULL;  //可燃气体传感器任务句柄
TaskHandle_t app_task_bluetooth_handle	= NULL;  //蓝牙任务句柄



/* 全局变量 */
uint8_t  g_init_end = 0;										// 初始化结束标志
uint8_t  g_esp8266_tx_buf[512]  = {0};     						// MQTT发送数据
volatile uint32_t g_esp8266_transparent_transmission_sta = 0;   // 记录MQTT当前是否为透传模式，1表示是，0表示否
volatile uint8_t  g_esp8266_rx_buf[512]  = {0};     			// MQTT接收数据
volatile uint32_t g_esp8266_rx_cnt       = 0;       			// MQTT接收的数据长度
volatile uint32_t g_esp8266_rx_end       = 0;       			// MQTT接收数据结束标志
char              g_mqtt_msg[256] = {0};						// MQTT发送的信息

uint32_t distance = 0;     // 超声波测距
float temperature = 0.0;   // 温度
float humidity = 0.0;      // 湿度

/* 火焰 */
volatile uint32_t adc_fire_val = 0;
volatile uint32_t adc_fire_vol = 0;
volatile uint8_t Flame_State = 0;

/* 可燃气体 */
volatile uint32_t adc_gas_val = 0;
volatile uint32_t adc_gas_vol = 0;
volatile uint8_t SmokeState = 0;


/*MFRC522数据区*/
u8  mfrc552pidbuf[18];
u8  card_pydebuf[2];
u8  card_numberbuf[5];
u8  card_password[16]={8,8,8,8,0,0,0,0,0,0,0,0,0,0,0,0}; 					//卡密（可修改）  
u8  card_key0Abuf[6]={0xff,0xff,0xff,0xff,0xff,0xff};						//密钥一,初始状态位6个0xff
u8  card_writebuf[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
u8  card_readbuf[18];


/* 事件标志组 */
EventGroupHandle_t	g_event_group;


/* 互斥型信号量句柄 */
SemaphoreHandle_t g_mutex_printf;
SemaphoreHandle_t g_mutex_dht;
SemaphoreHandle_t g_mutex_oled;


/* 消息队列句柄 */
QueueHandle_t g_queue_mqtt_send;  	 // 给MQTT发送数据的消息队列
QueueHandle_t g_queue_led;  		 // 控制LED亮灭的消息队列
QueueHandle_t g_queue_oled;			 // 控制OLED显示的消息队列
QueueHandle_t g_queue_beep;			 // 控制蜂鸣器的消息队列
QueueHandle_t g_queue_usart2;        // 串口2的消息队列
QueueHandle_t g_queue_rfid;        	 // rfid的消息队列


// 互斥锁
SemaphoreHandle_t xMutex;

/* 计数型信号量 */
SemaphoreHandle_t g_sem_led;
SemaphoreHandle_t g_sem_beep;
SemaphoreHandle_t g_sem_rfid;

/* 软件定时器句柄 */
TimerHandle_t soft_timer_Handle =NULL;   

/* 软件定时器 */
void soft_timer_callback(void* parameter);


int main(void)
{
	/* 设置系统中断优先级分组4 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	
	// 初始化串口1
	usart1_init(115200);
	
	// 初始化串口2
	usart2_init(9600);
	
	// 初始化串口3
	usart3_init(115200);
	
	/* 系统定时器中断频率为configTICK_RATE_HZ */
	SysTick_Config(SystemCoreClock/configTICK_RATE_HZ);			
	
	
	// 创建 app_task_init任务
	xTaskCreate((TaskFunction_t)app_task_init,			
				(const char *)"app_task_init",			
				(uint16_t)1024,							
				(void *)NULL,							
				(UBaseType_t)5,							
				(TaskHandle_t *)&app_task_init_handle); 
	
	// 开启任务调度
	vTaskStartScheduler();
	
	while(1);
}


/**
 @brief 使用信号量防止printf顺序出错
*/
int printf_safe(const char *format, ...)
{
	int n;
	va_list ap;
    va_start(ap, format);
	
	/* 获取互斥信号量 */
	xSemaphoreTake(g_mutex_printf, portMAX_DELAY);
	
    n = vprintf(format, ap);
	
	/* 释放互斥信号量 */
	xSemaphoreGive(g_mutex_printf);
	
    va_end(ap);
    return n;
}



void app_task_init(void *pvParameters)
{
	BaseType_t xReturn;
	
	printf("[app_task_init] create success\r\n");
	
	/* 创建互斥型信号量 */
	g_mutex_printf = xSemaphoreCreateMutex();
	g_mutex_dht = xSemaphoreCreateMutex();
	g_mutex_oled  	=xSemaphoreCreateMutex();	
	
	//创建互斥锁
	xMutex = xSemaphoreCreateMutex();
	
	
	/* 创建消息队列，能够支持6条消息，每条消息的大小为1字节 */
	g_queue_mqtt_send = xQueueCreate(6, sizeof(mqtt_sm_t));
	g_queue_led    	  = xQueueCreate(4, sizeof(uint8_t));	
	g_queue_beep      = xQueueCreate(16, sizeof(uint8_t));
	g_queue_oled      = xQueueCreate(16, sizeof(oled_t));	
	g_queue_usart2    = xQueueCreate(16, sizeof(struct usart2_packet));
	g_queue_rfid      = xQueueCreate(6, sizeof(uint8_t));
	
	/*创建事件标志组*/
	g_event_group = xEventGroupCreate();	
	
	/* 计数型信号量 */
	g_sem_led =xSemaphoreCreateCounting(255,0);	
	g_sem_beep=xSemaphoreCreateCounting(255,0);	
	g_sem_rfid=xSemaphoreCreateCounting(255,0);	
	
	
	// 初始化OLED
	OLED_Init();
	OLED_Clear();
	
	OLED_ShowString(0,0,"hello world",11);
	
	// led初始化
	led_init();
	
	// beep初始化
	beep_init();	
	
	// 按键初始化
	key_init();
	
	// 矩阵键盘初始化
	keyboard_init();
	
	// 定时器初始化
	rtc_init();
	
	// 定时器初始化
	tim3_init();
	
	// 温湿度传感器初始化
	dht11_init();
	
	// RFID初始化
	MFRC522_Initializtion();
	
	// 超声波模块初始化
	sr04_init();

	// ADC初始化
	adc1_init();
	adc2_init();
	exit9_init();
	exit1_init();
	ADC_SoftwareStartConv(ADC1);
	ADC_SoftwareStartConv(ADC2);

	// eeprom初始化
	eeprom_init();

	
	// 串口延迟一会，确保芯片内部完成全部初始化,printf无乱码输出
	delay_ms(500);
	
	// 打印开机信息
	printf_safe("This is esp8266 mqtt with aliyun test\n");
	
	while(esp8266_mqtt_init())
	{
		printf_safe("esp8266_mqtt_init ...\r\n");
		
		delay_ms(1000);
	}
	
	//连接服务器状态指示灯，点亮-连接成功
	CONNECT_MQTT_LED(1);

	printf_safe("esp8266 connect aliyun with mqtt success\r\n");	
	
	/*
	app_task_mqtt，任务函数
	"app_task_mqtt"，任务的名字
	1024，分配给任务1的内存（栈）大小，单位为字
	6,优先级为6，数值不能超过（configMAX_PRIORITIES -1）
	app_task_mqtt_handle，任务标志
	*/
	xReturn = xTaskCreate(app_task_mqtt_recv, "app_task_mqtt_recv", 1024, NULL, 6, &app_task_mqtt_recv_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_mqtt_recv fail\r\n");
	}	
	
	xReturn = xTaskCreate(app_task_mqtt_heart, "app_task_mqtt_heart", 256, NULL, 6, &app_task_mqtt_heart_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_mqtt_heart fail\r\n");
	}
	
	xReturn = xTaskCreate(app_task_mqtt_send, "app_task_mqtt_send", 1024, NULL, 6, &app_task_mqtt_send_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_mqtt_send fail\r\n");
	}	
	
	xReturn = xTaskCreate(app_task_dht, "app_task_dht", 512, NULL, 7, &app_task_dht_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_dht fail\r\n");
	}	
	
	xReturn = xTaskCreate(app_task_rfid, "app_task_rfid", 512, NULL, 7, &app_task_rfid_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_rfid fail\r\n");
	}

	xReturn = xTaskCreate(app_task_key, "app_task_key", 128, NULL, 7, &app_task_key_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_key fail\r\n");
	}	
	
	xReturn = xTaskCreate(app_task_keyboard, "app_task_keyboard", 256, NULL, 7, &app_task_keyboard_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_keyboard fail\r\n");
	}	
	
	xReturn = xTaskCreate(app_task_led, "app_task_led", 128, NULL, 7, &app_task_led_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_led fail\r\n");
	}

	xReturn = xTaskCreate(app_task_oled, "app_task_oled", 512, NULL, 6, &app_task_oled_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_oled fail\r\n");
	}
	
	xReturn = xTaskCreate(app_task_rtc, "app_task_rtc", 128, NULL, 6, &app_task_rtc_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_rtc fail\r\n");
	}
	
	xReturn = xTaskCreate(app_task_beep, "app_task_beep", 128, NULL, 7, &app_task_beep_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_beep fail\r\n");
	}
	
	xReturn = xTaskCreate(app_task_bluetooth, "app_task_bluetooth", 512, NULL, 6, &app_task_bluetooth_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_bluetooth fail\r\n");
	}
	
	xReturn = xTaskCreate(app_task_rfid_rw, "app_task_rfid_rw", 128, NULL, 7, &app_task_rfid_rw_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_rfid_rw fail\r\n");
	}
	
	xReturn = xTaskCreate(app_task_sr04, "app_task_sr04", 128, NULL, 7, &app_task_sr04_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_sr04 fail\r\n");
	}
	
	xReturn = xTaskCreate(app_task_adc_flame, "app_task_adc_flame", 128, NULL, 7, &app_task_adc_flame_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_adc_flame fail\r\n");
	}
	
	xReturn = xTaskCreate(app_task_adc_gas, "app_task_adc_gas", 128, NULL, 7, &app_task_adc_gas_handle);
	if(xReturn != pdPASS)
	{
		printf_safe("xTaskCreate app_task_adc_gas fail\r\n");
	}
	
	// 独立看门狗初始化，放在这里防止前面初始化超时导致复位
	iwdg_init();
	
	/* 创建周期软件定时器 */
	soft_timer_Handle=xTimerCreate(	(const char *)"AutoReloadTimer",
									(TickType_t)1000,/* 定时器周期 1000(tick) */
									(UBaseType_t)pdTRUE,/* 周期模式 */
									(void *)1,/* 为每个计时器分配一个索引的唯一ID */
									(TimerCallbackFunction_t)soft_timer_callback); 	
	/* 开启周期软件定时器 */							
	xTimerStart(soft_timer_Handle,0);	
	
				
	/* 创建用到的任务 开启中断 */
	taskENABLE_INTERRUPTS();   					
				
	/* 删除任务自身 */
	vTaskDelete(NULL);
				
	printf_safe("[app_task_init] nerver run here\r\n");

}



void app_task_mqtt_recv(void* pvParameters)
{
	uint32_t i=0;

	while(1)
	{
		
		//检查接收到数据
		if(g_esp8266_rx_end && g_esp8266_transparent_transmission_sta)
		{	
			for(i=0;i<g_esp8266_rx_cnt;i++)
			{	
				if(g_esp8266_rx_buf[i] == '{')
				{
					break;
				}
			}
			
			mqtt_cjson_parse((char *)&g_esp8266_rx_buf[i]);

			//清空接收缓冲区、接收计数值、接收结束标志位
			memset((void *)g_esp8266_rx_buf,0,sizeof g_esp8266_rx_buf);
			g_esp8266_rx_cnt=0;
			g_esp8266_rx_end=0;
		}
		delay_ms(1000);
		
	}
}


void app_task_mqtt_heart(void* pvParameters)
{	
	while(1)
	{
		mqtt_send_heart();
		//每隔1s发送一次心跳包
		delay_ms(30000);
	}
}



/**
 @brief MQTT消息组装
*/
void mqtt_msg_generate(char *pbuf, char *key, char *value)
{
	sprintf(pbuf,
            "{\"method\":\"thing.service.property.set\",\"id\":\"0001\",\"params\":{\
				\"%s\":%s},\
				\"version\":\"1.0.0\"}", key, value);
}


void app_task_mqtt_send(void* pvParameters)
{
	mqtt_sm_t g_mqtt_sm_t;
	BaseType_t xReturn = pdFALSE;
	
	while(1)
	{
		
		xReturn = xQueueReceive(g_queue_mqtt_send,	/* 消息队列的句柄 */
								&g_mqtt_sm_t,		/* 得到的消息内容 */
								portMAX_DELAY); 	/* 等待时间一直等 */
		if (xReturn != pdPASS)
		{
			printf_safe("[app_task_mqtt_send] mqtt_sm_t error code is %d\r\n", xReturn);
			continue;
		}
		
		switch(g_mqtt_sm_t.msg_type)
		{
			case TYPE_TEMPERATURE:
			{
				mqtt_msg_generate(g_mqtt_msg, "temperature", g_mqtt_sm_t.msg);
	
				//printf_safe("g_mqtt_msg temperature:%s\r\n",g_mqtt_msg);
				//等待互斥锁
				//xSemaphoreTake(xMutex, portMAX_DELAY);
				//上报信息到平台服务器
				mqtt_publish_data(MQTT_PUBLISH_TOPIC,g_mqtt_msg,0);
				//立即释放互斥锁
				//xSemaphoreGive(xMutex);
				break;
			}
			
			case TYPE_HUMIDITY:
			{
				mqtt_msg_generate(g_mqtt_msg, "humidity", g_mqtt_sm_t.msg);
	
				//printf_safe("g_mqtt_msg humidity:%s\r\n",g_mqtt_msg);
				//等待互斥锁
				//xSemaphoreTake(xMutex, portMAX_DELAY);
				//上报信息到平台服务器
				mqtt_publish_data(MQTT_PUBLISH_TOPIC,g_mqtt_msg,0);
				//立即释放互斥锁
				//xSemaphoreGive(xMutex);
				break;
			}
			
			case TYPE_SR04:
			{
				mqtt_msg_generate(g_mqtt_msg, "sr04_rang", g_mqtt_sm_t.msg);
	
				//printf_safe("g_mqtt_msg sr04_rang:%s\r\n",g_mqtt_msg);
				//等待互斥锁
				//xSemaphoreTake(xMutex, portMAX_DELAY);
				//上报信息到平台服务器
				mqtt_publish_data(MQTT_PUBLISH_TOPIC,g_mqtt_msg,0);
				//立即释放互斥锁
				//xSemaphoreGive(xMutex);
				break;
			}
			
			case TYPE_FLAME:
			{
				mqtt_msg_generate(g_mqtt_msg, "flame_state", g_mqtt_sm_t.msg);
	
				//printf_safe("g_mqtt_msg flame_state:%s\r\n",g_mqtt_msg);
				//等待互斥锁
				//xSemaphoreTake(xMutex, portMAX_DELAY);
				//上报信息到平台服务器
				mqtt_publish_data(MQTT_PUBLISH_TOPIC,g_mqtt_msg,0);
				//立即释放互斥锁
				//xSemaphoreGive(xMutex);
				break;
			}
			
			case TYPE_GAS_CONSISTENCY:
			{
				mqtt_msg_generate(g_mqtt_msg, "combustible_gas_consistency", g_mqtt_sm_t.msg);
		
				//printf_safe("g_mqtt_msg gas_consistency:%s\r\n",g_mqtt_msg);
				//等待互斥锁
				//xSemaphoreTake(xMutex, portMAX_DELAY);
				//上报信息到平台服务器
				mqtt_publish_data(MQTT_PUBLISH_TOPIC,g_mqtt_msg,0);
				//立即释放互斥锁
				//xSemaphoreGive(xMutex);
				break;
			}
			
			case TYPE_GAS_CHECK:
			{
				mqtt_msg_generate(g_mqtt_msg, "combustible_gas_check", g_mqtt_sm_t.msg);
	
				//printf_safe("g_mqtt_msg gas_check:%s\r\n",g_mqtt_msg);
				//等待互斥锁
				//xSemaphoreTake(xMutex, portMAX_DELAY);
				//上报信息到平台服务器
				mqtt_publish_data(MQTT_PUBLISH_TOPIC,g_mqtt_msg,0);
				//立即释放互斥锁
				//xSemaphoreGive(xMutex);
				break;
			}
			
			case LOCK_PICK_RECORD:
			{
				mqtt_msg_generate(g_mqtt_msg, "lock_pick_record", g_mqtt_sm_t.msg);
	
				//printf_safe("g_mqtt_msg gas_check:%s\r\n",g_mqtt_msg);
				//等待互斥锁
				//xSemaphoreTake(xMutex, portMAX_DELAY);
				//上报信息到平台服务器
				mqtt_publish_data(MQTT_PUBLISH_TOPIC,g_mqtt_msg,0);
				//立即释放互斥锁
				//xSemaphoreGive(xMutex);
				break;
			}
			
			default:
				break;
		}
		
		memset(&g_mqtt_sm_t, 0, sizeof(mqtt_sm_t));
		memset(g_mqtt_msg, 0, sizeof(g_mqtt_msg));
	}
}


void app_task_dht(void* pvParameters)
{
	mqtt_sm_t g_mqtt_sm_t;
	uint8_t	buf[5]={0};        // 存放温湿度
	uint8_t show_buf[16]={0};
	oled_t oled;
	BaseType_t xReturn;
	
	while(1)
	{
		if(0 == dht11_read(buf))
		{
			// 发送温度
			memset(&g_mqtt_sm_t, 0, sizeof(mqtt_sm_t));
			temperature = (float)buf[2]+(float)buf[3]/10;
			g_mqtt_sm_t.msg_type = TYPE_TEMPERATURE;
			sprintf(g_mqtt_sm_t.msg, "%.1f", temperature);
			//printf_safe("app_task_dht temperature:%s\r\n", g_mqtt_sm_t.msg);
			//等待互斥锁
			xSemaphoreTake(xMutex, portMAX_DELAY);
			//发送消息到消息队列，要求1秒内发送成功
			xQueueSend(g_queue_mqtt_send, &g_mqtt_sm_t, 1000);
			//立即释放互斥锁
			xSemaphoreGive(xMutex);
			
			// 发送湿度
			memset(&g_mqtt_sm_t, 0, sizeof(mqtt_sm_t));
			humidity = (float)buf[0]+(float)buf[1]/10;
			g_mqtt_sm_t.msg_type = TYPE_HUMIDITY;
			sprintf(g_mqtt_sm_t.msg, "%.1f", humidity);
			//printf_safe("app_task_dht humidity:%s\r\n", g_mqtt_sm_t.msg);
			//等待互斥锁
			xSemaphoreTake(xMutex, portMAX_DELAY);
			//发送消息到消息队列，要求1秒内发送成功
			xQueueSend(g_queue_mqtt_send, &g_mqtt_sm_t, 1000);
			//立即释放互斥锁
			xSemaphoreGive(xMutex);
			
			sprintf((char *)show_buf,"T:%.1f,H:%.1f", temperature, humidity);
			oled.ctrl=OLED_CTRL_SHOW_STRING;
			oled.x = 0;
			oled.y = 4;
			oled.str = show_buf;
			oled.font_size = 16;
			
			//等待互斥锁
			xSemaphoreTake(g_mutex_oled, portMAX_DELAY);
			xReturn = xQueueSend(g_queue_oled, &oled, 100);
			//立即释放互斥锁
			xSemaphoreGive(g_mutex_oled);
			
			
			
			if(xReturn != pdPASS)
				printf_safe("[app_task_dht] xQueueSend oled string error code is %d\r\n",xReturn);		
			
			// 清零
			memset((void *)buf, 0, sizeof(buf));
			memset((void *)&oled, 0, sizeof(oled));
			//temperature = 0.0;
			//humidity = 0.0;
		}
		// 间隔6s
		delay_ms(6000);
	}
}


void app_task_rfid(void* pvParameters)
{
	u8 i,status;
	mqtt_sm_t   g_mqtt_sm_t;
	RTC_DateTypeDef  RTC_DateStructure;
	RTC_TimeTypeDef  RTC_TimeStructure;
	
	while (1)
	{
		MFRC522_Initializtion();  //初始化MFRC522(有bug，每次都需初始化),需花一定的时序初始化
		status=MFRC522_Request(0x52, card_pydebuf);			//寻卡
		if(status==0)		//如果读到卡
		{
			status=MFRC522_Anticoll(card_numberbuf);			//防撞处理			
			MFRC522_SelectTag(card_numberbuf);	//选卡
			status=MFRC522_Auth(0x60, 4, card_key0Abuf, card_numberbuf);	//验卡
			//status=MFRC522_Write(4, card_writebuf);				//写卡（写卡要小心，特别是各区的块3）
			status=MFRC522_Read(4, card_readbuf);					//读卡
			//MFRC522_Halt();															//使卡进入休眠状态
			//卡类型显示
	
			printf_safe("card_pydebuf:%02X %02X\r\n",card_pydebuf[0],card_pydebuf[1]);
			
			//卡序列号显示，最后一字节为卡的校验码
			printf_safe("card_numberbuf:");
			for(i=0;i<5;i++)
			{
				printf("%02X ",card_numberbuf[i]);
			}
			printf_safe("\r\n");
			
			
			//密码判断
			for(i=0;i<4;i++)
			{
				if(card_readbuf[i] != card_password[i])
				{
					break;
				}
			}
			
			if(i!=4)
			{
				printf_safe("card error !!!\r\n");
				PFout(8)=1;
				delay_ms(1000);
				PFout(8)=0;
				continue;
			}
			printf_safe("card correct\r\n");

			PFout(8)=1;
			delay_ms(200);
			PFout(8)=0;
			
			// 发送开锁记录
			memset(&g_mqtt_sm_t, 0, sizeof(mqtt_sm_t));
			//获取日期时间
			RTC_GetDate(RTC_Format_BCD, &RTC_DateStructure);	
			RTC_GetTime(RTC_Format_BCD, &RTC_TimeStructure); 

			g_mqtt_sm_t.msg_type = LOCK_PICK_RECORD;
			sprintf(g_mqtt_sm_t.msg,"{\"mode\": 2,\"data_time\": \"%02x-%02x-%02x %02x:%02x:%02x\"}",
			RTC_DateStructure.RTC_Year,RTC_DateStructure.RTC_Month,RTC_DateStructure.RTC_Date,
			RTC_TimeStructure.RTC_Hours,RTC_TimeStructure.RTC_Minutes,RTC_TimeStructure.RTC_Seconds);
				
			//等待互斥锁
			xSemaphoreTake(xMutex, portMAX_DELAY);
			//发送消息到消息队列，要求1秒内发送成功
			xQueueSend(g_queue_mqtt_send, &g_mqtt_sm_t, 1000);
			//立即释放互斥锁
			xSemaphoreGive(xMutex);
		}	
		
		delay_ms(500);
	}
	
}


/*	按键中断事件	*/
void app_task_key(void* pvParameters)
{
	EventBits_t EventValue;
	//oled_t oled;
	//uint32_t pic_cur=0;	
	//uint32_t t=0;
	//BaseType_t xReturn;

	//const uint8_t *pic_tbl[]={pic1,pic2,pic3,pic4,pic5};

		
	//printf_safe("[app_task_key] create success\r\n");
	
	for(;;)
	{
		/* 等待事件组中的相应事件位，或同步 */
		EventValue=xEventGroupWaitBits((EventGroupHandle_t	)g_event_group,		
									   (EventBits_t			)EVENT_GROUP_KEYALL_DOWN,
									   (BaseType_t			)pdTRUE,				
									   (BaseType_t			)pdFALSE,
									   (TickType_t			)portMAX_DELAY);
		if(EventValue & EVENT_GROUP_KEY1_DOWN)
		{
			/* 禁止EXTI0触发中断 */
			NVIC_DisableIRQ(EXTI0_IRQn);
			
			/* 延时消抖 */
			delay_ms(50);

			/* 确认是按下 */
			if(PAin(0) == 0)
			{				
				printf_safe("[app_task_key] S1 Press\r\n");
				
				#if 0
				t=0;

				/* 按键长按 */
				while(PAin(0)==0)
				{
					delay_ms(1);
					
					if(t++ >= 2000)											
						break;			
				}
				
				if(t>=2000)
				{
					xEventGroupSetBits(g_event_group,EVENT_GROUP_SYSTEM_RESET);
				}
				else
				{
					printf_safe("[app_task_key] S1 Suppend Task\r\n");

					/* 挂起其他任务，独占屏幕 */
					vTaskSuspend(app_task_rtc_handle);			
					vTaskSuspend(app_task_dht_handle);
					vTaskSuspend(app_task_sr04_handle);
					vTaskSuspend(app_task_rfid_handle);
					oled.ctrl=OLED_CTRL_SHOW_PICTURE;
					oled.x=0;
					oled.y=0;
					oled.pic_width=128;
					oled.pic_height=8;				
					oled.pic=pic5;

					xReturn = xQueueSend( 	g_queue_oled,/* 消息队列的句柄 */
											&oled,		/* 发送的消息内容 */
											100);		/* 等待时间 100 Tick */
					if(xReturn != pdPASS)
						printf_safe("[app_task_key] xQueueSend oled picture error code is %d\r\n",xReturn);									
				}			
				#endif
			}
			
			/* 允许EXTI0触发中断 */
			NVIC_EnableIRQ(EXTI0_IRQn);	
		}
		
		if(EventValue & EVENT_GROUP_KEY2_DOWN)
		{
			/* 禁止EXTI2触发中断 */
			NVIC_DisableIRQ(EXTI2_IRQn);
			
			/* 延时消抖 */
			delay_ms(50);
				
			if(PEin(2) == 0)
			{
				printf_safe("[app_task_key] S2 Press\r\n");
				
				#if 0
				/* 等待按键释放 */
				while(PEin(2)==0)
					vTaskDelay(1);
				
				if(pic_cur < 5)
				{
					vTaskSuspend(app_task_rtc_handle);			
					vTaskSuspend(app_task_dht_handle);
					vTaskSuspend(app_task_sr04_handle);
					vTaskSuspend(app_task_rfid_handle);
					oled.ctrl=OLED_CTRL_SHOW_PICTURE;
					oled.x=0;
					oled.y=0;
					oled.pic_width=128;
					oled.pic_height=8;

					oled.pic=pic_tbl[pic_cur++];
					
					xReturn = xQueueSend( 	g_queue_oled,/* 消息队列的句柄 */
											&oled,		 /* 发送的消息内容 */
											100);		 /* 等待时间 100 Tick */
					if(xReturn != pdPASS)
						printf_safe("[app_task_key] xQueueSend oled picture error code is %d\r\n",xReturn);									
				}		
				#endif
			}

			/* 允许EXTI2触发中断 */
			NVIC_EnableIRQ(EXTI2_IRQn);	
		}	
		
		if(EventValue & EVENT_GROUP_KEY3_DOWN)
		{
			/* 禁止EXTI3触发中断 */
			NVIC_DisableIRQ(EXTI3_IRQn);
			
			/* 延时消抖 */
			delay_ms(50);
				
			if(PEin(3) == 0)
			{
				printf_safe("[app_task_key] S3 Press\r\n");
				
				#if 0
				/* 等待按键释放 */
				while(PEin(3)==0)
					vTaskDelay(1);
				
				if(pic_cur)
				{
					vTaskSuspend(app_task_rtc_handle);			
					vTaskSuspend(app_task_dht_handle);
					vTaskSuspend(app_task_sr04_handle);
					vTaskSuspend(app_task_rfid_handle);
					pic_cur--;
					
					oled.ctrl=OLED_CTRL_SHOW_PICTURE;
					oled.x=0;
					oled.y=0;
					oled.pic_width=128;
					oled.pic_height=8;					
					oled.pic=pic_tbl[pic_cur];
					
					xReturn = xQueueSend( 	g_queue_oled,/* 消息队列的句柄 */
											&oled,		/* 发送的消息内容 */
											100);		/* 等待时间 100 Tick */
					if(xReturn != pdPASS)
						printf_safe("[app_task_key] xQueueSend oled picture error code is %d\r\n",xReturn);							
				
				}	
				#endif
			}
			
			/* 允许EXTI3触发中断 */
			NVIC_EnableIRQ(EXTI3_IRQn);	
		}
		
		if(EventValue & EVENT_GROUP_KEY4_DOWN)
		{
			/* 禁止EXTI4触发中断 */
			NVIC_DisableIRQ(EXTI4_IRQn);
			
			/* 延时消抖 */
			delay_ms(50);
				
			if(PEin(4) == 0)	
			{
				printf_safe("[app_task_key] S4 Press\r\n");
				
				#if 0
				t=0;
				/* 按键长按，控制对OLED屏的亮灭 */
				while(PEin(4)==0)
				{
					vTaskDelay(1);
					
					if(t++ >= 2000)
						break;		
				}
				
				if(t>=2000)
				{
					/* 进入临界区 */
					taskENTER_CRITICAL();
					
					g_oled_display_flag=!g_oled_display_flag;
					
					/* 退出临界区 */
					taskEXIT_CRITICAL();
					
					oled.ctrl=g_oled_display_flag?OLED_CTRL_DISPLAY_ON:OLED_CTRL_DISPLAY_OFF;

					xReturn = xQueueSend( 	g_queue_oled,/* 消息队列的句柄 */
											&oled,		/* 发送的消息内容 */
											100);		/* 等待时间 100 Tick */
					if(xReturn != pdPASS)
						printf_safe("[app_task_key] xQueueSend oled error code is %d\r\n",xReturn);								
				}
				else
				{
					vTaskSuspend(app_task_rfid_handle);
					printf_safe("[app_task_key] S4 Resume Task\r\n");

					pic_cur=0;
					
					/* OLED清屏 */
					oled.ctrl=OLED_CTRL_CLEAR;

					xReturn = xQueueSend( 	g_queue_oled,/* 消息队列的句柄 */
											&oled,	/* 发送的消息内容 */
											100);		/* 等待时间 100 Tick */
					
					/* 恢复其他任务 */
					vTaskResume(app_task_rtc_handle);			
					vTaskResume(app_task_dht_handle);
					vTaskResume(app_task_sr04_handle);						
				}	
				#endif
			}
			
			/* 允许EXTI4触发中断 */
			NVIC_EnableIRQ(EXTI4_IRQn);	
		}			
	}
} 

/*	矩阵键盘事件	*/
void app_task_keyboard(void* pvParameters)
{
	u8 			i=0;
	BaseType_t 	xReturn=pdFALSE;
	oled_t		oled;
	uint8_t 	buf_pw[8]={0};
	uint8_t 	buf_welcome[16]={0};
	uint8_t 	buf_error[16]={0};
	uint8_t 	beep_sta=0;
	uint8_t		led_sta=0;		
	uint8_t 	password[7] = {0};
	uint8_t 	master_pw[9]={0};
	mqtt_sm_t   g_mqtt_sm_t;
	RTC_DateTypeDef  RTC_DateStructure;
	RTC_TimeTypeDef  RTC_TimeStructure;
	uint32_t key_sta=0;
	char key_cur=0;
	char key_old=0;
	
	/* 读取存储在at24c02 地址1的数据密码 */
	eeprom_read(16,master_pw,6);
	printf_safe("master_pw = %s\r\n", (char *)master_pw);
	
	while(1)
	{
		/* 使用状态机思想得到按键的状态 */
		switch(key_sta)
		{
			case 0://获取按下的按键
			{
				
				key_cur = get_key_board();	

				if(key_cur != 'N')
				{
					key_old = key_cur;
					key_sta=1;
				}
					
			}break;
						
			case 1://确认按下的按键
			{
				
				key_cur = get_key_board();	//接收键盘数据，然后传输改密码等
					
				if((key_cur != 'N') && (key_cur == key_old))
				{
					printf_safe("KEY %c Down\r\n",key_cur);
					
					key_sta=2;	
					if(key_cur == '*')//清零
					{
						for(i=0;i<6;i++)
						{
							password[i]=0;
						}
						i = 0;	
					}
					else if(key_cur == '#')//退一位密码
					{
						password[i]=0;
						i--;
					}
					else
					{
						password[i]=key_cur;
						i++;
					}
					
					beep_sta=1;
					xQueueSend(g_queue_beep, &beep_sta, 100);
					vTaskDelay(100);
					beep_sta=0;
					xQueueSend(g_queue_beep, &beep_sta, 100);
				}
				
			}break;
		
			case 2://获取释放的按键
			{
				key_cur = get_key_board();	
					
				if(key_cur == 'N')
				{
					printf_safe("KEY %c Up\r\n",key_old);
					
					key_sta=0;
					
					key_old =  'N';	

				}
					
			}break;

			default:break;
		}
		vTaskDelay(10);
		if(i == 6)
		{			
			vTaskSuspend(app_task_dht_handle);
			vTaskSuspend(app_task_rtc_handle);
			vTaskSuspend(app_task_sr04_handle);
			/* OLED清屏 */
			oled.ctrl=OLED_CTRL_CLEAR;
			xQueueSend(g_queue_oled,&oled,100);	

			i=0;
			
			/* 格式化字符串 */
			sprintf((char *)buf_pw,"pw:%s",password);
			printf_safe("[app_task_rtc] %s\r\n",buf_pw);
			
			/* oled显示 */
			oled.ctrl=OLED_CTRL_SHOW_STRING;
			oled.x=0;
			oled.y=2;
			oled.str=buf_pw;
			oled.font_size=16;

			xReturn = xQueueSend(g_queue_oled,&oled, 100);
									
			if(xReturn != pdPASS)
				printf_safe("[app_task_rtc] xQueueSend oled string error code is %d\r\n",xReturn);

			if(strcmp((char *)password, (char *)master_pw)==0) //密码123456
			{	
				led_sta = 10;

				xQueueSend(g_queue_led,&led_sta,100);
				sprintf((char *)buf_welcome,"welcome!");
				/* oled显示 */
				oled.ctrl=OLED_CTRL_SHOW_STRING;
				oled.x=32;
				oled.y=0;
				oled.str=buf_welcome;
				oled.font_size=16;

				xReturn = xQueueSend(g_queue_oled, &oled, 100);

				BEEP(1);
				vTaskDelay(100);
				BEEP(0);
				vTaskDelay(100);
				BEEP(1);
				vTaskDelay(100);
				BEEP(0);
				vTaskDelay(1000);
				
				led_sta = 11;
				xQueueSend(g_queue_led,&led_sta,100);
				
				// 发送开锁记录
				memset(&g_mqtt_sm_t, 0, sizeof(mqtt_sm_t));
				//获取日期时间
				RTC_GetDate(RTC_Format_BCD, &RTC_DateStructure);	
				RTC_GetTime(RTC_Format_BCD, &RTC_TimeStructure); 

				g_mqtt_sm_t.msg_type = LOCK_PICK_RECORD;
				sprintf(g_mqtt_sm_t.msg,"{\"mode\": 1,\"data_time\": \"%02x-%02x-%02x %02x:%02x:%02x\"}",
				RTC_DateStructure.RTC_Year,RTC_DateStructure.RTC_Month,RTC_DateStructure.RTC_Date,
				RTC_TimeStructure.RTC_Hours,RTC_TimeStructure.RTC_Minutes,RTC_TimeStructure.RTC_Seconds);
				
				//等待互斥锁
				xSemaphoreTake(xMutex, portMAX_DELAY);
				//发送消息到消息队列，要求1秒内发送成功
				xQueueSend(g_queue_mqtt_send, &g_mqtt_sm_t, 1000);
				//立即释放互斥锁
				xSemaphoreGive(xMutex);
			
			}else //密码错误
			{
				BEEP(1);
				xSemaphoreTake(g_mutex_oled,portMAX_DELAY);
				sprintf((char *)buf_error,"pw is error!");
				/* oled显示 */
				oled.ctrl=OLED_CTRL_SHOW_STRING;
				oled.x=0;
				oled.y=4;
				oled.str=buf_error;
				oled.font_size=16;

				xReturn = xQueueSend(g_queue_oled ,&oled, 100);
				xSemaphoreGive(g_mutex_oled);
				vTaskDelay(1000);
				BEEP(0);
			}
			vTaskDelay(2000);
			/* OLED清屏 */
			oled.ctrl=OLED_CTRL_CLEAR;
			xQueueSend(g_queue_oled,&oled,100);	
			
			vTaskResume(app_task_rtc_handle);			
			vTaskResume(app_task_dht_handle);
			vTaskResume(app_task_sr04_handle);				
			
		}
	}
}


/*	led消息队列		*/
void app_task_led(void* pvParameters)
{
	uint8_t led_sta=0;	
	BaseType_t xReturn=pdFALSE;	
	
	while(1)
	{
		xReturn = xQueueReceive( g_queue_led,	/* 消息队列的句柄 */
								&led_sta, 		/* 得到的消息内容 */
								portMAX_DELAY);	/* 等待时间一直等 */
		
		if(xReturn != pdPASS)
			continue;
		
		switch(led_sta)
		{
			case 10:
			{
				/* LED1亮 */
				PFout(9) = 0;
			}break;

			case 11:
			{
				/* LED1灭 */
				PFout(9) = 1;
			}break;

			case 20:
			{
				/* LED2亮 */
				PFout(10) = 0;
			}break;

			case 21:
			{
				/* LED2灭 */
				PFout(10) = 1;
			}break;

			case 30:
			{
				/* LED3亮 */
				PEout(13) = 0;
			}break;

			case 31:
			{
				/* LED3灭 */
				PEout(13) = 1;
			}break;

			case 40:
			{
				/* LED4亮 */
				PEout(14) = 0;
			}break;

			case 41:
			{
				/* LED4灭 */
				PEout(14) = 1;
			}break;
			default:printf_safe("[app_task_led] led ctrl code is invalid\r\n");	
				break;
		}
	}
}   


/*	OLED消息队列	*/
void app_task_oled(void* pvParameters)
{
	oled_t oled;
	BaseType_t xReturn=pdFALSE;	

	while(1)
	{
		xReturn = xQueueReceive( g_queue_oled,	/* 消息队列的句柄 */
								&oled, 			/* 得到的消息内容 */
								portMAX_DELAY);	/* 等待时间一直等 */

		if(xReturn != pdPASS)
			continue;
		
		//printf_safe("oled.ctrl=%d,oled.x=%d,oled.y=%d,oled.str=%s,oled.font_size=%d\r\n",oled.ctrl,oled.x,oled.y,oled.str,oled.font_size);
		
		switch(oled.ctrl)
		{
			case OLED_CTRL_DISPLAY_ON:
			{
				/* 亮屏 */
				OLED_Display_On();
			}break;

			case OLED_CTRL_DISPLAY_OFF:
			{
				/* 灭屏 */
				OLED_Display_Off();	
			}break;

			case OLED_CTRL_CLEAR:
			{
				/* 清屏 */
				OLED_Clear();
			}break;

			case OLED_CTRL_SHOW_STRING:
			{
				/* 显示字符串 */
				OLED_ShowString(oled.x,oled.y,oled.str,oled.font_size);
			}break;

			case OLED_CTRL_SHOW_CHINESE:
			{
				/* 显示汉字 */
				OLED_ShowCHinese(oled.x,
								oled.y,
								oled.chinese);
			}break;			

			case OLED_CTRL_SHOW_PICTURE:
			{
				/* 显示图片 */
				OLED_DrawBMP(	oled.x,
								oled.y,
								oled.x+oled.pic_width,
								oled.y+oled.pic_height,
								oled.pic);
			}break;

			default:printf_safe("[app_task_oled] oled ctrl code is invalid\r\n");	
				break;
		}
						
	}
}

/*	RTC中断获取实时时间	*/
void app_task_rtc(void* pvParameters)
{
	uint8_t 		time_buf[16]={0};
	uint8_t 		data_buf[64]={0};	
	oled_t			oled;
	BaseType_t		xReturn;
	//EventBits_t 	EventValue;
	RTC_TimeTypeDef RTC_TimeStructure;
	RTC_DateTypeDef RTC_DateStructure;	
	
	while(1)
	{
		// 获取时间
		RTC_GetTime(RTC_Format_BCD, &RTC_TimeStructure); 
			
		/* 格式化字符串 */
		sprintf((char *)time_buf,"%02x:%02x:%02x",RTC_TimeStructure.RTC_Hours,RTC_TimeStructure.RTC_Minutes,RTC_TimeStructure.RTC_Seconds);
		
		/* oled显示时间 */
		
		oled.ctrl=OLED_CTRL_SHOW_STRING;
		oled.x=30;
		oled.y=2;
		oled.str=time_buf;
		oled.font_size=16;

		xReturn = xQueueSend(g_queue_oled, &oled, 100);
		
		if(xReturn != pdPASS)
			printf_safe("[app_task_rtc] xQueueSend oled string error code is %d\r\n",xReturn);			
		
		//printf_safe("[app_task_rtc] time_buf %s\r\n",time_buf);

		//获取日期
		RTC_GetDate(RTC_Format_BCD,&RTC_DateStructure);	

		sprintf((char *)data_buf,"Y:%02x M:%02x D:%02x %1x",RTC_DateStructure.RTC_Year,RTC_DateStructure.RTC_Month,RTC_DateStructure.RTC_Date,RTC_DateStructure.RTC_WeekDay);
		
		/* oled显示日期 */
		oled.ctrl=OLED_CTRL_SHOW_STRING;
		oled.x=0;
		oled.y=0;
		oled.str=data_buf;
		oled.font_size=16;

		xReturn = xQueueSend(g_queue_oled, &oled, 100);
		
		if(xReturn != pdPASS)
			printf_safe("[app_task_rtc] xQueueSend oled string error code is %d\r\n",xReturn);			
		
		//printf_safe("[app_task_rtc] data_buf %s\r\n",data_buf);
			
		delay_ms(1000);
	}
}   

/*	蜂鸣消息队列	*/
void app_task_beep(void* pvParameters)
{
	uint8_t beep_sta=0;	
	BaseType_t xReturn=pdFALSE;	
	
	while(1)
	{
		xReturn = xQueueReceive( g_queue_beep,	/* 消息队列的句柄 */
								&beep_sta, 		/* 得到的消息内容 */
								portMAX_DELAY);	/* 等待时间一直等 */
		if(xReturn != pdPASS)
			continue;
		
		if(beep_sta)
			BEEP(1);
		else
			BEEP(0);

		/* 释放信号量，告诉对方，当前beep控制任务已经完成 */
		xSemaphoreGive(g_sem_beep);		
	}
} 


/*	蓝牙操作 */
void app_task_bluetooth(void *pvParameters)
{
	static struct usart2_packet g_usart2_packet={0};
	mqtt_sm_t g_mqtt_sm_t;
	BaseType_t xReturn = pdFALSE;
	int32_t tmp				=0;
	uint8_t buf[9]			={0};
	uint8_t password[7]		={0};
	uint8_t i = 0;
	char send_buf[64];    // 发送给蓝牙数据
	//uint32_t alarm_distance = 0;
	char *p = NULL;	
	//oled_t    oled;
	
	RTC_DateTypeDef  RTC_DateStructure;
	RTC_TimeTypeDef  RTC_TimeStructure;
	RTC_AlarmTypeDef  RTC_AlarmStructure;	
	
	
	//配置蓝牙模块的名字
	usart2_send_str("AT+NAMESSSTTTY\r\n");
	//获取模块的地址信息，因为通过手机搜索的时候，
   //使用提供的APK，有些时候无法显示到模块的名字，只能显示到模块的地址信息
	usart2_send_str("AT+LADDR\r\n");
	delay_ms(500);
 
   //重新启动模块
 	usart2_send_str("AT+RESET\r\n");
	delay_ms(2000);	
	
	while(1)
	{
		xReturn = xQueueReceive(g_queue_usart2,	/* 消息队列的句柄 */
								&g_usart2_packet,	/* 得到的消息内容 */
								portMAX_DELAY); /* 等待时间一直等 */
		if (xReturn != pdPASS)
		{
			printf_safe("[app_task_usart] xQueueReceive usart_packet error code is %d\r\n", xReturn);
			continue;
		}
		
		printf_safe("g_queue_usart2 recv_buf = %s\r\n", g_usart2_packet.recv_buf);
		//开锁
		if(strstr((char *)g_usart2_packet.recv_buf,"UNLOCK"))  //UNLOCK-8-8-8-8# 
		{
			//用"-"分割字符串
			p = strtok((char *)g_usart2_packet.recv_buf,"-");
			
			//读取第1位
			p = strtok(NULL,"-");
			buf[0] = (uint8_t)atoi(p);

			//读取第2位
			p = strtok(NULL,"-");
			buf[1] = (uint8_t)atoi(p);
			
			//读取第3位
			p = strtok(NULL,"-");
			buf[2] = (uint8_t)atoi(p);
			
			//读取第4位
			p = strtok(NULL,"-");
			buf[3] = (uint8_t)atoi(p);
			
			/* 进入临界区，任务和抢占优先级较低的硬件中断无法打断其执行 */
			taskENTER_CRITICAL();
			
			for(i=0; i<4 ;i++)
			{
				if(card_password[i] != buf[i])
				{
					break;
				}
			}
			
			
			/* 退出临界区，告诉内核已经保护完毕 */
			taskEXIT_CRITICAL();
			
			if(i != 4)
			{
				sprintf(send_buf, "%s", "Password error!!!\r\n");
				usart2_send_str(send_buf);
				PFout(8)=1;
				delay_ms(1000);
				PFout(8)=0;
			}
			else
			{
				// 发送开锁记录
				memset(&g_mqtt_sm_t, 0, sizeof(mqtt_sm_t));
				//获取日期时间
				RTC_GetDate(RTC_Format_BCD, &RTC_DateStructure);	
				RTC_GetTime(RTC_Format_BCD, &RTC_TimeStructure); 

				g_mqtt_sm_t.msg_type = LOCK_PICK_RECORD;
				sprintf(g_mqtt_sm_t.msg,"{\"mode\": 3,\"data_time\": \"%02x-%02x-%02x %02x:%02x:%02x\"}",
				RTC_DateStructure.RTC_Year,RTC_DateStructure.RTC_Month,RTC_DateStructure.RTC_Date,
				RTC_TimeStructure.RTC_Hours,RTC_TimeStructure.RTC_Minutes,RTC_TimeStructure.RTC_Seconds);
				
				//等待互斥锁
				xSemaphoreTake(xMutex, portMAX_DELAY);
				//发送消息到消息队列，要求1秒内发送成功
				xQueueSend(g_queue_mqtt_send, &g_mqtt_sm_t, 1000);
				//立即释放互斥锁
				xSemaphoreGive(xMutex);
				
				sprintf(send_buf, "%s", "Unlock success\r\n");
				usart2_send_str(send_buf);
				PFout(8)=1;
				delay_ms(200);
				PFout(8)=0;
			}
			
		}
		
		//设置RTC日期
		if(strstr((char *)g_usart2_packet.recv_buf,"DATE SET"))  //DATE SET-2022-9-23-5# 
		{
			//用"-"分割字符串
			p = strtok((char *)g_usart2_packet.recv_buf,"-");
			
			//读取年
			p = strtok(NULL,"-");
			tmp = ((atoi(p)-2000)/10)*16+(atoi(p)-2000)%10;
			RTC_DateStructure.RTC_Year = tmp;
			
			//读取月
			p = strtok(NULL,"-");
			tmp = (atoi(p)/10)*16+atoi(p)%10;
			RTC_DateStructure.RTC_Month=tmp;
			
			//读取日
			p = strtok(NULL,"-");
			tmp = (atoi(p)/10)*16+atoi(p)%10;
			RTC_DateStructure.RTC_Date=tmp;
			
			//读取星期几
			p = strtok(NULL,"-");
			tmp = (atoi(p)/10)*16+atoi(p)%10;
			RTC_DateStructure.RTC_WeekDay=tmp;
			RTC_SetDate(RTC_Format_BCD, &RTC_DateStructure);
		
		}
		//设置RTC时间
		if(strstr((char *)g_usart2_packet.recv_buf,"TIME SET"))  // TIME SET-10-20-30#
		{
			//用"-"分割字符串
			p = strtok((char *)g_usart2_packet.recv_buf,"-");
			
			//读取小时
			p = strtok(NULL,"-");
			tmp = (atoi(p)/10)*16+atoi(p)%10;
				RTC_TimeStructure.RTC_Hours  = tmp;
			
			//读取分钟
			p = strtok(NULL,"-");
			tmp = (atoi(p)/10)*16+atoi(p)%10;
			RTC_TimeStructure.RTC_Minutes=tmp;
			
			//读取秒
			p = strtok(NULL,"-");
			tmp = (atoi(p)/10)*16+atoi(p)%10;
			RTC_TimeStructure.RTC_Seconds=tmp;
			RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure);
					
		}
		//设置闹钟时间
		if(strstr((char *)g_usart2_packet.recv_buf,"ALARM SET")) //  ALARM SET-14-20-10#
		{
			//用"-"分割字符串
			p = strtok((char *)g_usart2_packet.recv_buf,"-");
			
			//读取小时
			p = strtok(NULL,"-");
			tmp = atoi(p);
			if(tmp>12)
				RTC_AlarmStructure.RTC_AlarmTime.RTC_H12 = RTC_H12_PM;//下午
			else
				RTC_AlarmStructure.RTC_AlarmTime.RTC_H12 = RTC_H12_AM; //上午
			
			tmp = (atoi(p)/10)*16+atoi(p)%10;
			RTC_AlarmStructure.RTC_AlarmTime.RTC_Hours = tmp;
			
			//读取分钟
			p = strtok(NULL,"-");
			tmp = (atoi(p)/10)*16+atoi(p)%10;
			RTC_AlarmStructure.RTC_AlarmTime.RTC_Minutes=tmp;
			
			//读取秒
			p = strtok(NULL,"-");
			tmp = (atoi(p)/10)*16+atoi(p)%10;
			RTC_AlarmStructure.RTC_AlarmTime.RTC_Seconds=tmp;
			RTC_AlarmStructure.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay;	//屏蔽日期和星期，就是闹钟每天都生效
			
			/* 关闭闹钟，若不关闭，配置闹钟触发的中断有bug，无论怎么配置，只要到00秒都会触发中断*/
			RTC_AlarmCmd(RTC_Alarm_A, DISABLE);

			/* 配置RTC的A闹钟 */
			RTC_SetAlarm(RTC_Format_BCD, RTC_Alarm_A, &RTC_AlarmStructure);

			/* 让RTC的A闹钟工作 */
			RTC_AlarmCmd(RTC_Alarm_A, ENABLE);				
		}	
		//设置卡密
		if(strstr((char *)g_usart2_packet.recv_buf,"CARD PW SET"))  //  CARD PW SET-8-8-8-8#
		{						
			//用"-"分割字符串
			p = strtok((char *)g_usart2_packet.recv_buf,"-");
			
			//读取第1位
			p = strtok(NULL,"-");
			buf[0] = (uint8_t)atoi(p);

			//读取第2位
			p = strtok(NULL,"-");
			buf[1] = (uint8_t)atoi(p);
			
			//读取第3位
			p = strtok(NULL,"-");
			buf[2] = (uint8_t)atoi(p);
			
			//读取第4位
			p = strtok(NULL,"-");
			buf[3] = (uint8_t)atoi(p);
			
			/* 进入临界区，任务和抢占优先级较低的硬件中断无法打断其执行 */
			taskENTER_CRITICAL();
			
			card_password[0] = buf[0];
			card_password[1] = buf[1];
			card_password[2] = buf[2];
			card_password[3] = buf[3];
			
			/* 退出临界区，告诉内核已经保护完毕 */
			taskEXIT_CRITICAL();
			
			printf_safe("card_password : %d %d %d %d\r\n",
			card_password[0],card_password[1],card_password[2],card_password[3]);
			
			usart2_send_str("card passwd set success\r\n");
			
		}
		//写入卡密到卡
		if(strstr((char *)g_usart2_packet.recv_buf,"CARD PW WR"))  //  CARD PW WR
		{						
			uint8_t card_act = 0x02;
			//等待互斥锁
			xSemaphoreTake(xMutex, portMAX_DELAY);
			//发送消息到消息队列，要求0.2秒内发送成功
			xQueueSend(g_queue_rfid, &card_act, 200);
			//立即释放互斥锁
			xSemaphoreGive(xMutex);
			
			printf_safe("[app_task_bluetooth] xSemaphoreTake CARD PW WR \r\n");
			
			/* 阻塞等待信号量，用于确保任务完成写卡密 */
			xReturn=xSemaphoreTake(g_sem_rfid,portMAX_DELAY);					
			if(xReturn != pdPASS)
				printf_safe("[app_task_bluetooth] xSemaphoreTake g_sem_rfid error code is %d\r\n",xReturn);
			
			usart2_send_str("card passwd write success\r\n");
			
		}
		//设置矩阵键盘密码
		if(strstr((char *)g_usart2_packet.recv_buf,"KEY SET"))  //  KEY SET-456789
		{
			//用"-"分割字符串
			p = strtok((char *)g_usart2_packet.recv_buf,"-");
			
			//读取第1位
			p = strtok(NULL,"-");
			
			sprintf((char *)password,p);		
			
			/* 进入临界区，任务和抢占优先级较低的硬件中断无法打断其执行 */
			taskENTER_CRITICAL();
			
			eeprom_write(16,password,6);
			
			/* 退出临界区，告诉内核已经保护完毕 */
			taskEXIT_CRITICAL();
			
			usart2_send_str("Setup succeeded,Please restart\r\n");

			memset(password,0,sizeof password);			
		}		
		//查询温度
		if(strcmp((char *)g_usart2_packet.recv_buf,"TEMP\n")==0)
		{
			sprintf(send_buf, "%.1f\r\n", temperature);
			usart2_send_str(send_buf);
		}
		//查询湿度
		if(strcmp((char *)g_usart2_packet.recv_buf,"HUMI\n")==0)
		{
			sprintf(send_buf, "%.1f %%RH\r\n", humidity);
			usart2_send_str(send_buf);
		}
		//查询日期
		if(strcmp((char *)g_usart2_packet.recv_buf,"DATE\n")==0)
		{
			//获取日期
			RTC_GetDate(RTC_Format_BCD,&RTC_DateStructure);	

			sprintf(send_buf,"Y:%02x M:%02x D:%02x %1x\n",RTC_DateStructure.RTC_Year,RTC_DateStructure.RTC_Month,RTC_DateStructure.RTC_Date,RTC_DateStructure.RTC_WeekDay);
			usart2_send_str(send_buf);
				
		}
		//查询时间		
		if(strcmp((char *)g_usart2_packet.recv_buf,"TIME\n")==0)
		{
			/* RTC_GetTime，获取时间 */
			RTC_GetTime(RTC_Format_BCD, &RTC_TimeStructure); 
			sprintf(send_buf,"%02x:%02x:%02x\n",RTC_TimeStructure.RTC_Hours,RTC_TimeStructure.RTC_Minutes,RTC_TimeStructure.RTC_Seconds);
			usart2_send_str(send_buf);
		}
		//查询超声波状态
		if(strcmp((char *)g_usart2_packet.recv_buf,"SR04\n")==0)
		{
			sprintf(send_buf, "%d mm %%RH\r\n", distance);
			usart2_send_str(send_buf);
		}
		//查询火焰状态
		if(strcmp((char *)g_usart2_packet.recv_buf,"FLAME\n")==0)
		{
			if(Flame_State == 0)
			{
				usart2_send_str("无火\r\n");
			}
			else 
			{
				usart2_send_str("有火\r\n");
			}
		}
		//查询气体状态
		if(strcmp((char *)g_usart2_packet.recv_buf,"GAS\n")==0)
		{
			if(SmokeState == 0)
			{
				usart2_send_str("未检测到可燃气体\r\n");
			}
			else 
			{
				usart2_send_str("检测到可燃气体\r\n");
			}
		}
		
		//查询所有状态
		if(strcmp((char *)g_usart2_packet.recv_buf,"ALL\n")==0)
		{
			sprintf(send_buf, "T=%.1f\n", temperature);
			usart2_send_str(send_buf);
			sprintf(send_buf, "H=%.1f\n", humidity);
			usart2_send_str(send_buf);
			
			//获取日期
			RTC_GetDate(RTC_Format_BCD,&RTC_DateStructure);	
			sprintf(send_buf,"Y:%02x M:%02x D:%02x %1x\n",RTC_DateStructure.RTC_Year,RTC_DateStructure.RTC_Month,RTC_DateStructure.RTC_Date,RTC_DateStructure.RTC_WeekDay);
			usart2_send_str(send_buf);
			
			/* 获取时间 */
			RTC_GetTime(RTC_Format_BCD, &RTC_TimeStructure); 
			sprintf(send_buf,"%02x:%02x:%02x\n",RTC_TimeStructure.RTC_Hours,RTC_TimeStructure.RTC_Minutes,RTC_TimeStructure.RTC_Seconds);
			usart2_send_str(send_buf);
			
			sprintf(send_buf, "distance=%d mm %%RH\n", distance);
			usart2_send_str(send_buf);
			sprintf(send_buf, "flame=%d\n", Flame_State);
			usart2_send_str(send_buf);
			sprintf(send_buf, "gas=%d\n", SmokeState);
			usart2_send_str(send_buf);
		}
		
		i = 0;
		memset(send_buf, 0, sizeof(send_buf));
		
	}
}


/*	读写卡数据  */
void app_task_rfid_rw(void* pvParameters)
{
	uint8_t rfid_sta=0,status,i=0;	
	BaseType_t xReturn = pdFALSE;
	
	while(1)
	{
		
		xReturn = xQueueReceive(g_queue_rfid, &rfid_sta, portMAX_DELAY);	/* 等待时间一直等 */
		if(xReturn != pdPASS)
			printf_safe("[app_task_rfid_rw] error code is %d\r\n",xReturn);		
		vTaskSuspend(app_task_rfid_handle);  // 挂起
		MFRC522_Initializtion(); //初始化MFRC522(有bug，每次都需初始化),需花一定的时序初始化
		while(1)
		{
			// 等10s，如果不放卡就走
			if(i>50)
			{
				break;
			}
			status=MFRC522_Request(0x52, card_pydebuf);			//寻卡
			if(status==0)		//如果读到卡
			{
				status=MFRC522_Anticoll(card_numberbuf);			//防撞处理			
				MFRC522_SelectTag(card_numberbuf);	//选卡
				status=MFRC522_Auth(0x60, 4, card_key0Abuf, card_numberbuf);	//验卡
			
				status=MFRC522_Write(4, card_password);				//写卡（写卡要小心，特别是各区的块3）
				if(status == 0){
					printf_safe("write card success\r\n");
					PFout(8)=1;
					delay_ms(200);
					PFout(8)=0;
					break;
				}
			}	
			i++;
			delay_ms(200);
		}
		vTaskResume(app_task_rfid_handle);	// 恢复

		/* 释放信号量，告诉对方，当前任务已经完成 */
		xSemaphoreGive(g_sem_rfid);		
		i=0;
	}
} 



/*	超声波  */
void app_task_sr04(void* pvParameters)
{
	mqtt_sm_t g_mqtt_sm_t;
	BaseType_t 	xReturn=pdFALSE;
	oled_t		oled;
	uint8_t 	buf_sr04[8]={0};
	
	vTaskDelay(4000);
	
	while(1)
	{
		distance=sr04_get_distance();
		
		if(distance==0xFFFFFFFF)
		{
			//模块有可能没有连接好，连接错引脚或杜邦线松动
			printf_safe("sr04 is error\r\n");
		}
		else if(distance <20 || distance >4000)
		{
			//数据是异常的
			printf_safe("sr04 get distance is error\r\n");		
		}
		else 
		{
			if(distance>=20 && distance<=200)
			{
				PEout(14)=0;
				vTaskDelay(50);
				PEout(14)=1;
				vTaskDelay(50);
				PEout(14)=0;
				vTaskDelay(50);
				PEout(14)=1;
					
				BEEP(1);
				vTaskDelay(500);
				BEEP(0);
			}
			/* 显示 */
			sprintf((char *)buf_sr04,"sr04:%d mm",distance);
			//printf_safe("[app_task_sr04]%s\r\n",buf_sr04);
			
			/* oled显示 */
			oled.ctrl=OLED_CTRL_SHOW_STRING;
			oled.x=0;
			oled.y=6;
			oled.str=buf_sr04;
			oled.font_size=16;
				
			xReturn = xQueueSend(g_queue_oled, &oled, 100);			
			if(xReturn != pdPASS)
				printf_safe("[app_task_rtc] xQueueSend oled string error code is %d\r\n",xReturn);
			
			// 发送MQTT
			memset(&g_mqtt_sm_t, 0, sizeof(mqtt_sm_t));
			g_mqtt_sm_t.msg_type = TYPE_SR04;
			sprintf(g_mqtt_sm_t.msg, "%d", distance);

			//等待互斥锁
			xSemaphoreTake(xMutex, portMAX_DELAY);
			//发送消息到消息队列，要求1秒内发送成功
			xQueueSend(g_queue_mqtt_send, &g_mqtt_sm_t, 1000);
			//立即释放互斥锁
			xSemaphoreGive(xMutex);
			
		}

		//延时1500ms
		vTaskDelay(1000);
	}
}

/*	火焰传感器  */
void app_task_adc_flame(void* pvParameters)
{
	mqtt_sm_t g_mqtt_sm_t;
	
	vTaskDelay(3000);
	
	while(1)
	{
		adc_fire_val = ADC_GetConversionValue(ADC1);
		adc_fire_vol = 3300*adc_fire_val/4095;
		printf_safe("adc_fire_val = %d\r\n",adc_fire_val);
		printf_safe("adc_fire_vol = %dmv\r\n",adc_fire_vol);
		if(adc_fire_val < 3000)
		{
			Flame_State = 1;
			printf_safe("[app_task_adc_fire] Fire!Fire!Fire!\r\n");		
			BEEP(1);
			vTaskDelay(500);
			BEEP(0);
		}
		else
		{
			Flame_State = 0;
		}
		
		// 发送MQTT
		memset(&g_mqtt_sm_t, 0, sizeof(mqtt_sm_t));
		g_mqtt_sm_t.msg_type = TYPE_FLAME;
		sprintf(g_mqtt_sm_t.msg, "%d", Flame_State);

		//等待互斥锁
		xSemaphoreTake(xMutex, portMAX_DELAY);
		//发送消息到消息队列，要求1秒内发送成功
		xQueueSend(g_queue_mqtt_send, &g_mqtt_sm_t, 1000);
		//立即释放互斥锁
		xSemaphoreGive(xMutex);
		
		vTaskDelay(6000);
	}
}


/*	可燃气体传感器  */
void app_task_adc_gas(void* pvParameters)
{
	mqtt_sm_t g_mqtt_sm_t;
	
	vTaskDelay(3500);
	
	while(1)
	{
		adc_gas_val = ADC_GetConversionValue(ADC2);
		adc_gas_vol = 3300*adc_gas_val/4095;
		//printf_safe("adc_gas_val = %d\r\n",adc_gas_val);
		//printf_safe("adc_gas_vol = %dmv\r\n",adc_gas_vol);
		if(adc_gas_vol > 800)
		{
			SmokeState = 1;
			printf_safe("[app_task_adc_gas] gas!gas!gas!\r\n");		
			BEEP(1);
			vTaskDelay(500);
			BEEP(0);
		}
		else 
		{
			SmokeState = 0;
		}
		
		// 发送MQTT
		memset(&g_mqtt_sm_t, 0, sizeof(mqtt_sm_t));
		g_mqtt_sm_t.msg_type = TYPE_GAS_CHECK;
		sprintf(g_mqtt_sm_t.msg, "%d", SmokeState);

		//等待互斥锁
		xSemaphoreTake(xMutex, portMAX_DELAY);
		//发送消息到消息队列，要求1秒内发送成功
		xQueueSend(g_queue_mqtt_send, &g_mqtt_sm_t, 1000);
		//立即释放互斥锁
		xSemaphoreGive(xMutex);
		
		vTaskDelay(6000);
	}
}


/*  看门狗 */
void soft_timer_callback(void* parameter)
{		
	/* 关闭中断 */
	portDISABLE_INTERRUPTS();
	
	/* 喂狗，刷新自身计数值 */
	IWDG_ReloadCounter();	
	
	/* 打开中断 */
	portENABLE_INTERRUPTS();
} 


/**
 @brief 解析JSON
*/
void mqtt_cjson_parse(char *pbuf)
{
	cJSON *json , *json_params, *json_id, *json_method, *json_humidity, *json_temperature,*json_sr04_rang, 
	*json_flame_state, *json_gas_check, *json_switch_led_1, *json_switch_led_2, *json_switch_led_3, *json_switch_led_4;
	
	char *p = pbuf;
		
	//解析数据包
	json = cJSON_Parse(p);			
	if (!json)  
	{  
		cJSON_Delete(json);
		json=NULL;		
		return;
	} 		
	
	printf("\n");
	
	//根据method键获取值
	json_method = cJSON_GetObjectItem(json ,"method"); 
	if(json_method->type == cJSON_String)
	{
		printf_safe("method:%s\r\n", json_method->valuestring);  
	}	
	
	//根据id键获取值			
	json_id = cJSON_GetObjectItem(json , "id"); 
	if(json_id->type == cJSON_String)
	{
		printf_safe("id:%s\r\n", json_id->valuestring);  
	}	
	
	//根据params键获取值
	json_params = cJSON_GetObjectItem(json , "params"); 
	if(json_params)
	{
		//根据键获取值
		//humidity
		json_humidity=cJSON_GetObjectItem(json_params , "humidity"); 
		if(json_humidity && json_humidity->type == cJSON_Number)
		{
			printf_safe("humidity:%.1f\r\n", json_humidity->valuedouble);  
		}
		
		//temperature
		json_temperature=cJSON_GetObjectItem(json_params , "temperature"); 
		if(json_temperature && json_temperature->type == cJSON_Number)
		{
			printf_safe("temperature:%.1f\r\n", json_temperature->valuedouble);  
		}
		
		//sr04_rang
		json_sr04_rang=cJSON_GetObjectItem(json_params , "sr04_rang"); 
		if(json_sr04_rang && json_sr04_rang->type == cJSON_Number)
		{
			printf_safe("sr04_rang:%d\r\n", json_sr04_rang->valueint);  
		}
		
		//flame_state
		json_flame_state=cJSON_GetObjectItem(json_params , "flame_state"); 
		if(json_flame_state && json_flame_state->type == cJSON_Number)
		{
			printf_safe("flame_state:%d\r\n", json_flame_state->valueint);  
		}
		
		//combustible_gas_check
		json_gas_check=cJSON_GetObjectItem(json_params , "combustible_gas_check"); 
		if(json_gas_check && json_gas_check->type == cJSON_Number)
		{
			printf_safe("combustible_gas_check:%d\r\n", json_gas_check->valueint);  
		}
		
		//json_switch_led_1
		json_switch_led_1=cJSON_GetObjectItem(json_params , "swtich_led_1"); 
		if(json_switch_led_1 && json_switch_led_1->type == cJSON_Number)
		{
			printf_safe("swtich_led_1:%d\r\n", json_switch_led_1->valueint);  
			PFout(9) = json_switch_led_1->valueint;
		}
		
		//json_switch_led_2
		json_switch_led_2=cJSON_GetObjectItem(json_params , "switch_led_2"); 
		if(json_switch_led_2 && json_switch_led_2->type == cJSON_Number)
		{
			printf_safe("swtich_led_2:%d\r\n", json_switch_led_2->valueint);  
			PFout(10) = json_switch_led_2->valueint;
		}
		
		//json_switch_led_3
		json_switch_led_3=cJSON_GetObjectItem(json_params , "swtich_led_3"); 
		if(json_switch_led_3 && json_switch_led_3->type == cJSON_Number)
		{
			printf_safe("swtich_led_3:%d\r\n", json_switch_led_3->valueint);  
			PEout(13) = json_switch_led_3->valueint;
		}
		
		//json_switch_led_4
		json_switch_led_4=cJSON_GetObjectItem(json_params , "swtich_led_4"); 
		if(json_switch_led_4 && json_switch_led_4->type == cJSON_Number)
		{
			printf_safe("swtich_led_4:%d\r\n", json_switch_led_4->valueint);  
			PEout(14) = json_switch_led_4->valueint;
		}
					
	}
	printf("\n");
	cJSON_Delete(json);
	json=NULL;	
}

	

/*-----------------------------------------------------------*/

void vApplicationMallocFailedHook( void )
{
	/* vApplicationMallocFailedHook() will only be called if
	configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook
	function that will get called if a call to pvPortMalloc() fails.
	pvPortMalloc() is called internally by the kernel whenever a task, queue,
	timer or semaphore is created.  It is also called by various parts of the
	demo application.  If heap_1.c or heap_2.c are used, then the size of the
	heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
	FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
	to query the size of free heap space that remains (although it does not
	provide information on how the remaining heap might be fragmented). */
	taskDISABLE_INTERRUPTS();
	for( ;; );
}
/*-----------------------------------------------------------*/

void vApplicationIdleHook( void )
{
	/* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
	to 1 in FreeRTOSConfig.h.  It will be called on each iteration of the idle
	task.  It is essential that code added to this hook function never attempts
	to block in any way (for example, call xQueueReceive() with a block time
	specified, or call vTaskDelay()).  If the application makes use of the
	vTaskDelete() API function (as this demo application does) then it is also
	important that vApplicationIdleHook() is permitted to return to its calling
	function, because it is the responsibility of the idle task to clean up
	memory allocated by the kernel to any task that has since been deleted. */
}
/*-----------------------------------------------------------*/

void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
{
	( void ) pcTaskName;
	( void ) pxTask;

	/* Run time stack overflow checking is performed if
	configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2.  This hook
	function is called if a stack overflow is detected. */
	taskDISABLE_INTERRUPTS();
	for( ;; );
}


void vApplicationTickHook( void )
{

}
